/* Convert from a XenoLinux major device to the Xen-level 'physical' device */
static inline unsigned short xldev_to_physdev(kdev_t xldev)
{
- unsigned short physdev;
+ unsigned short physdev = 0;
switch ( MAJOR(xldev) )
{
case XLVIRT_MAJOR:
physdev = XENDEV_VIRTUAL;
break;
-
- default:
- BUG();
}
+ if ( physdev == 0 ) BUG();
+
physdev += (MINOR(xldev) >> PARTN_SHIFT);
return physdev;
return gd;
}
+
+static inline xl_disk_t *xldev_to_xldisk(kdev_t xldev)
+{
+ struct gendisk *gd = xldev_to_gendisk(xldev);
+ return (xl_disk_t *)gd->real_devices + (MINOR(xldev) >> PARTN_SHIFT);
+}
+
+
int xenolinux_block_open(struct inode *inode, struct file *filep)
{
- DPRINTK("xenolinux_block_open\n");
+ xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
+ disk->usage++;
+ DPRINTK("xenolinux_block_open\n");
return 0;
}
+
int xenolinux_block_release(struct inode *inode, struct file *filep)
{
+ xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev);
+ disk->usage--;
DPRINTK("xenolinux_block_release\n");
return 0;
}
-
int xenolinux_block_ioctl(struct inode *inode, struct file *filep,
unsigned command, unsigned long argument)
{
+ kdev_t dev = inode->i_rdev;
struct hd_geometry *geo = (struct hd_geometry *)argument;
struct gendisk *gd;
struct hd_struct *part;
if (!inode) return -EINVAL;
DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
- command, (long) argument, inode->i_rdev);
+ command, (long) argument, dev);
- gd = xldev_to_gendisk(inode->i_rdev);
- part = &gd->part[MINOR(inode->i_rdev)];
+ gd = xldev_to_gendisk(dev);
+ part = &gd->part[MINOR(dev)];
switch ( command )
{
case BLKRRPART: /* re-read partition table */
DPRINTK_IOCTL(" BLKRRPART: %x\n", BLKRRPART);
- break;
+ if ( !capable(CAP_SYS_ADMIN) ) return -EACCES;
+ return xenolinux_block_revalidate(dev);
case BLKSSZGET:
- switch ( MAJOR(inode->i_rdev) )
+ switch ( MAJOR(dev) )
{
case XLIDE_MAJOR:
DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlide_hwsect(MINOR(inode->i_rdev)));
- return xlide_hwsect(MINOR(inode->i_rdev));
+ xlide_hwsect(MINOR(dev)));
+ return xlide_hwsect(MINOR(dev));
case XLSCSI_MAJOR:
DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlscsi_hwsect(MINOR(inode->i_rdev)));
- return xlscsi_hwsect(MINOR(inode->i_rdev));
+ xlscsi_hwsect(MINOR(dev)));
+ return xlscsi_hwsect(MINOR(dev));
case XLVIRT_MAJOR:
DPRINTK_IOCTL(" BLKSSZGET: %x 0x%x\n", BLKSSZGET,
- xlsegment_hwsect(MINOR(inode->i_rdev)));
- return xlsegment_hwsect(MINOR(inode->i_rdev));
+ xlsegment_hwsect(MINOR(dev)));
+ return xlsegment_hwsect(MINOR(dev));
default:
printk(KERN_ALERT "BLKSSZGET ioctl() on bogus disk!\n");
int xenolinux_block_revalidate(kdev_t dev)
{
- DPRINTK("xenolinux_block_revalidate\n");
+ struct gendisk *gd = xldev_to_gendisk(dev);
+ xl_disk_t *disk = xldev_to_xldisk(dev);
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&io_request_lock, flags);
+ if ( disk->usage > 1 )
+ {
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&io_request_lock, flags);
+
+ for ( i = 0; i < (1 << PARTN_SHIFT); i++ )
+ {
+ invalidate_device(dev + i, 1);
+ gd->part[dev + i].start_sect = 0;
+ gd->part[dev + i].nr_sects = 0;
+ }
+
+ grok_partitions(gd, MINOR(dev) >> PARTN_SHIFT,
+ 1 << PARTN_SHIFT, disk->capacity);
+
return 0;
}
+
/*
* hypervisor_request
*
#define DPRINTK_IOCTL(_f, _a...) ((void)0)
#endif
+/*
+ * We have one of these per XL-IDE, XL-SCSI, and XL-VIRT device.
+ * They hang in an array off the gendisk structure. We may end up putting
+ * all kinds of interesting stuff here :-)
+ */
+typedef struct xl_disk {
+ int usage;
+ unsigned long capacity;
+} xl_disk_t;
+
/* Generic layer. */
extern int xenolinux_control_msg(int operration, char *buffer);
extern int xenolinux_block_open(struct inode *inode, struct file *filep);
for ( i = 0; i < xdi->count; i++ )
if ( xdi->disks[i].type == XEN_DISK_IDE ) units++;
+ if ( units == 0 ) return 0;
+
/* Construct an appropriate gendisk structure. */
minors = units * (1<<IDE_PARTN_BITS);
gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
gd->minor_shift = IDE_PARTN_BITS;
gd->max_p = 1<<IDE_PARTN_BITS;
gd->nr_real = units;
- gd->real_devices = NULL;
+ gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
gd->next = NULL;
gd->fops = &xlide_block_fops;
gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
memset(gd->part, 0, minors * sizeof(struct hd_struct));
memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
memset(gd->flags, 0, sizeof(*gd->flags) * units);
+ memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
xlide_gendisk = gd;
add_gendisk(gd);
-
+
/* Now register each disk in turn. */
disk = 0;
for ( i = 0; i < xdi->count; i++ )
{
if ( xdi->disks[i].type != XEN_DISK_IDE ) continue;
+ ((xl_disk_t *)gd->real_devices)[disk].capacity =
+ xdi->disks[i].capacity;
register_disk(gd,
MKDEV(XLIDE_MAJOR, disk<<IDE_PARTN_BITS),
1<<IDE_PARTN_BITS,
xdi->disks[i].capacity);
disk++;
}
-
+
printk(KERN_ALERT
"XenoLinux Virtual IDE Device Driver installed [device: %d]\n",
XLIDE_MAJOR);
for ( i = 0; i < xdi->count; i++ )
if ( xdi->disks[i].type == XEN_DISK_SCSI ) units++;
+ if ( units == 0 ) return 0;
+
/* Construct an appropriate gendisk structure. */
minors = units * (1<<SCSI_PARTN_BITS);
gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
gd->minor_shift = SCSI_PARTN_BITS;
gd->max_p = 1<<SCSI_PARTN_BITS;
gd->nr_real = units;
- gd->real_devices = NULL;
+ gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
gd->next = NULL;
gd->fops = &xlscsi_block_fops;
gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
memset(gd->part, 0, minors * sizeof(struct hd_struct));
memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
memset(gd->flags, 0, sizeof(*gd->flags) * units);
+ memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
xlscsi_gendisk = gd;
add_gendisk(gd);
for ( i = 0; i < xdi->count; i++ )
{
if ( xdi->disks[i].type != XEN_DISK_SCSI ) continue;
+ ((xl_disk_t *)gd->real_devices)[disk].capacity =
+ xdi->disks[i].capacity;
register_disk(gd,
MKDEV(XLSCSI_MAJOR, disk<<SCSI_PARTN_BITS),
1<<SCSI_PARTN_BITS,
for ( i = 0; i < xdi->count; i++ )
if ( xdi->disks[i].type == XEN_DISK_VIRTUAL ) units++;
+ if ( units == 0 ) return 0;
+
/* Construct an appropriate gendisk structure. */
minors = units * (1<<VIRT_PARTN_BITS);
gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
gd->minor_shift = VIRT_PARTN_BITS;
gd->max_p = 1<<VIRT_PARTN_BITS;
gd->nr_real = units;
- gd->real_devices = NULL;
+ gd->real_devices = kmalloc(units * sizeof(xl_disk_t), GFP_KERNEL);
gd->next = NULL;
gd->fops = &xlsegment_block_fops;
gd->de_arr = kmalloc(sizeof(*gd->de_arr) * units, GFP_KERNEL);
memset(gd->part, 0, minors * sizeof(struct hd_struct));
memset(gd->de_arr, 0, sizeof(*gd->de_arr) * units);
memset(gd->flags, 0, sizeof(*gd->flags) * units);
+ memset(gd->real_devices, 0, sizeof(xl_disk_t) * units);
xlsegment_gendisk = gd;
add_gendisk(gd);
for ( i = 0; i < xdi->count; i++ )
{
if ( xdi->disks[i].type != XEN_DISK_VIRTUAL ) continue;
+ ((xl_disk_t *)gd->real_devices)[disk].capacity =
+ xdi->disks[i].capacity;
register_disk(gd,
MKDEV(XLVIRT_MAJOR, disk<<VIRT_PARTN_BITS),
1<<VIRT_PARTN_BITS,